package com.yqg.protection.netty.handler;

import com.yqg.protection.netty.service.Sdf300RegisterService;
import com.yqg.protection.utils.ByteUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;

@Component
@Slf4j
@ChannelHandler.Sharable
public class Sdf300RegisterHandler extends AbstractProtocolHandler implements DynamicProtocolHandler {

    @Autowired
    private Sdf300RegisterService sdf300RegisterService;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            if (msg instanceof ByteBuf) {
                ByteBuf buf = (ByteBuf) msg;
                String hexData = ByteBufUtil.hexDump(buf).toUpperCase();
                log.info("收到设备注册包原始数据: {}", hexData);

                // 创建ProtocolData对象
                ProtocolData protocolData = new ProtocolData();
                protocolData.setHeader(hexData.substring(0,2));
                protocolData.setRawData(hexData);
                protocolData.setCtx(ctx);
                protocolData.setSaveTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

                // 生成并发送响应
                byte[] response = generateRegisterResponse(buf);
                ctx.writeAndFlush(Unpooled.wrappedBuffer(response));
                log.info("已发送FD协议响应");

                // 调用处理逻辑
                handle(protocolData);
            } else {
                log.warn("收到非ByteBuf类型数据: {}", msg.getClass().getName());
                ctx.fireChannelRead(msg);
            }
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

    private void handle(ProtocolData protocolData) {
        String rawData = protocolData.getRawData();
        // 将十六进制字符串转换为字节数组
        byte[] allBytes = ByteUtil.toBytes(rawData);
        // 用字节数组创建一个ByteBuf
        ByteBuf buf = Unpooled.wrappedBuffer(allBytes);
        // 跳过HEADER (1字节 0xFD)
        buf.readByte();

        // 读取LEN (2字节，大端序)
        int dataLen = buf.readShort();

        // 验证数据长度
        if (buf.readableBytes() < dataLen + 2) { // +2 for CRC
            log.error("数据长度不足，期望: {} 字节，实际: {} 字节",
                     dataLen + 2, buf.readableBytes());
            return;
        }

        // 读取DATA部分
        byte[] dataBytes = new byte[dataLen];
        buf.readBytes(dataBytes);

        // 读取CRC (2字节)
        short receivedCrc = buf.readShort();

        // 验证CRC (根据协议文档实现)
        short calculatedCrc = calculateCrc16(dataBytes);
        if (receivedCrc != calculatedCrc) {
            log.error("CRC校验失败，接收: {}, 计算: {}",
                     String.format("%04X", receivedCrc),
                     String.format("%04X", calculatedCrc));
            return;
        }

        // 解析DATA部分
        int position = 0;

        // IMEI (16字节 ASCII)
        String imei = new String(dataBytes, position, 16, StandardCharsets.US_ASCII).trim();
        position += 16;

        // IMSI (16字节 ASCII)
        String imsi = new String(dataBytes, position, 16, StandardCharsets.US_ASCII).trim();
        position += 16;

        // UID (16字节)
        byte[] uidBytes = new byte[16];
        System.arraycopy(dataBytes, position, uidBytes, 0, 16);
        String uid = bytesToHex(uidBytes);
        position += 16;

        // LA: 4级地址 (8字节 = 4个short)
        int[] la = new int[4];
        for (int i = 0; i < 4; i++) {
            la[i] = ((dataBytes[position++] & 0xFF) << 8) | (dataBytes[position++] & 0xFF);
        }

        // ADDRESS MODE (1字节)
        int addressMode = dataBytes[position++] & 0xFF;

        // ID TYPE (1字节)
        int idType = dataBytes[position++] & 0xFF;

        // UP MODE (1字节)
        int upMode = dataBytes[position++] & 0xFF;

        // UP TIME (2字节)
        int upTime = ((dataBytes[position++] & 0xFF) << 8) | (dataBytes[position++] & 0xFF);

        // UP UNIT (1字节)
        int upUnit = dataBytes[position++] & 0xFF;

        // RESERVED (2字节)
        int reserved = ((dataBytes[position++] & 0xFF) << 8) | (dataBytes[position++] & 0xFF);

        log.info("解析设备注册包: IMEI={}, IMSI={}, UID={}, LA={}-{}-{}-{}, " +
                 "addressMode={}, idType={}, upMode={}, upTime={}, upUnit={}, reserved={}",
                 imei, imsi, uid, la[0], la[1], la[2], la[3],
                 addressMode, idType, upMode, upTime, upUnit, reserved);

        String sendTime = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(new Date());
        // 保存注册信息
        executor.execute(() -> dataSaver.saveDataToFileAsync(protocolData.getRawData(), sendTime, imei));
        executor.execute(() ->
            sdf300RegisterService.saveRegistration(
                imei, imsi, uid, la, addressMode, idType,
                upMode, upTime, upUnit, reserved, sendTime
            )
        );
    }

    private byte[] generateRegisterResponse(ByteBuf buf) {
        buf.markReaderIndex();
        try {
            // 跳过HEADER (1字节 0xFD)
            if (buf.readableBytes() < 1) {
                log.error("数据不足，无法读取HEADER");
                return null;
            }
            buf.readByte(); // 跳过0xFD

            // 读取LEN (2字节，大端序)
            if (buf.readableBytes() < 2) {
                log.error("数据不足，无法读取LEN");
                return null;
            }
            int dataLen = buf.readShort(); // DATA部分长度

            // 检查可读字节数是否足够（DATA+CRC）
            if (buf.readableBytes() < dataLen + 2) {
                log.error("数据长度不足，期望: {} 字节，实际: {} 字节", dataLen + 2, buf.readableBytes());
                return null;
            }

            // 读取IMEI (16字节)
            if (buf.readableBytes() < 16) {
                log.error("数据不足，无法读取IMEI");
                return null;
            }
            byte[] imeiBytes = new byte[16];
            buf.readBytes(imeiBytes); // 读取IMEI

            // 构建响应包
            // HEADER: 0xFE
            // LEN: 0x0014 (20字节) - 包括后续所有DATA部分
            // DATA: [内部LEN(1B), CTR(1B), ADDR(16B), VALUE(2B)]
            byte[] dataPart = new byte[20];
            int pos = 0;
            dataPart[pos++] = 0x13; // 内部LEN: 后续19字节(CTR+ADDR+VALUE)
            dataPart[pos++] = 0x00; // CTR: 无需应答
            System.arraycopy(imeiBytes, 0, dataPart, pos, 16); // ADDR: IMEI
            pos += 16;
            dataPart[pos++] = (byte) 0xAA; // VALUE: 0xAA
            dataPart[pos] = (byte) 0x55;   // VALUE: 0x55

            // 计算DATA部分的CRC16
            short crc = calculateCrc16(dataPart);

            // 构建完整响应
            ByteBuf responseBuf = Unpooled.buffer(25); // 1(HEADER) + 2(LEN) + 20(DATA) + 2(CRC)
            responseBuf.writeByte(0xFE); // HEADER
            responseBuf.writeShort(20);  // LEN: 0x0014
            responseBuf.writeBytes(dataPart); // DATA
            responseBuf.writeByte(crc & 0xFF); // CRC低字节
            responseBuf.writeByte((crc >> 8) & 0xFF); // CRC高字节

            byte[] response = new byte[responseBuf.readableBytes()];
            responseBuf.readBytes(response);
            return response;
        } catch (Exception e) {
            log.error("生成注册响应异常", e);
            return null;
        } finally {
            buf.resetReaderIndex();
        }
    }

    // 根据协议文档实现CRC16校验
    private short calculateCrc16(byte[] data) {
        // 实现CRC16算法（参考协议文档第11-13页）
        // 简化的实现，实际应按照文档实现
        int crc = 0xFFFF;
        for (byte b : data) {
            crc = (crc ^ (b & 0xFF));
            for (int i = 0; i < 8; i++) {
                if ((crc & 0x0001) != 0) {
                    crc = (crc >> 1) ^ 0xA001;
                } else {
                    crc = crc >> 1;
                }
            }
        }
        return (short) crc;
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString();
    }

    @Override
    public String supportHeader() {
        return "FD";
    }
}
